//------------------------------------------------------------------------------ 
//      Copyright (c) 2004-2009, Be Nanashi-San 
// 
//      Permission is hereby granted, free of charge, to any person obtaining a 
//      copy of this software and associated documentation files (the "Software"), 
//      to deal in the Software without restriction, including without limitation 
//      the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//      and/or sell copies of the Software, and to permit persons to whom the 
//      Software is furnished to do so, subject to the following conditions: 
// 
//      The above copyright notice and this permission notice shall be included in 
//      all copies or substantial portions of the Software. 
// 
//      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
//      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
//      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
//      FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
//      DEALINGS IN THE SOFTWARE. 
// 
//      File Name:   2chPositive.cpp
//      Author:      Be Nanashi-San 
//      Description: 2chPositive application class. 
//------------------------------------------------------------------------------

#include "config.h"
#include "config_user.h"

#include <Alert.h>
#include <Autolock.h>
#include <Directory.h>
#include <File.h>
#include <FindDirectory.h>
#include <MenuItem.h>
#include <Path.h>
#include <PopUpMenu.h>
#include <ScrollBar.h>
#include <stdlib.h>
#include <string.h>
#include <Entry.h>
#include "2chPositive.h"
#include "FindWindow.h"
#include "JumpWindow.h"
#include "PrefWindow.h"
#include "ThreadWriteWindow.h"
#include "mainWindow.h"
#include "messages.h"
#include "setting.h"
#include "TSettings.h"
#include "Rev.h"

//Readers
#include "BBSHandler.h"
#ifdef USE_2CH
#include "BBS2chReader.h"
#endif
#ifdef USE_PINKBBS
#include "BBSPinkchReader.h"
#endif
#ifdef USE_MACHIBBS
#include "BBSMachibbsReader.h"
#endif
#ifdef USE_LOCALDAT
#include "LocalDATReader.h"
#endif
#ifdef USE_MYBBS
#include "BBSMyReader.h"
#endif

////////////////////////////////////////////////////////////////////////////////
// main
//
//
////////////////////////////////////////////////////////////////////////////////
int
main(int /*argc*/, char** /*argv*/)
{	
	a2chViewer	the2chViewer;

	the2chViewer.Run();

	return(EXIT_SUCCESS);
}
////////////////////////////////////////////////////////////////////////////////
// a2chViewer
//
//
////////////////////////////////////////////////////////////////////////////////
a2chViewer::a2chViewer()
: BApplication("application/x-vnd.Noname-2chPositive")
,fMainWindow(NULL)
,fFindWindow(NULL)
,fJumpWindow(NULL)
,fPrefWindow(NULL)
,fWriteWindow(NULL)
,fTarget(0)
,fFindString(NULL)
{
	this->MakeSettingDir();
	this->LoadReader();
	if(theSettings().Load()!= B_OK)
		this->MakeDefault();
	
	fMainWindow = new mainWindow(theSettings().GetRect(kSETTING_WINDOW_RECT));
	fMainWindow->Show();
}
////////////////////////////////////////////////////////////////////////////////
// QuitRequested
// 設定の保存など。
//
////////////////////////////////////////////////////////////////////////////////
bool
a2chViewer::QuitRequested()
{
	bool ret = BApplication::QuitRequested();
	if (ret){
		this->ReleaseReader();
	}
	return ret;
}
////////////////////////////////////////////////////////////////////////////////
// AboutRequested
//
//
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::AboutRequested()
{
	(new BAlert("","2chPositive ver. " REVDAYS "\n(Revision : " REVS ")\n\nBy Be名無しさん","OK"))->Go();
}
/////////////////////////////////////////////////////////////////////////////////
// DoFind
//
// 20060813:msgを使い廻すように修正
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::DoFind(BMessage *msg, bool findagain)
{
	if(!findagain){
		msg->FindString("findthis", &fFindString);
		msg->FindInt32("targetview", &fTarget); //10/26修正
	}

	//zeta 2 スレ@713のBe名無しさんより。NULLの場合追加。
	if (!fFindString.Length()) return;	// NULLの場合落ちるので

	if(findagain){
		msg->what = kMSG_FIND;
		msg->AddString("findthis", fFindString);
		msg->AddInt32("targetview", fTarget);
	}

	BMessenger(fMainWindow).SendMessage(msg);
}
/////////////////////////////////////////////////////////////////////////////////
// OpenWriteThreadWindow
//
//
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::OpenWriteThreadWindow(BMessage *message)
{
	if(!fWriteWindow)
		fWriteWindow = new ThreadWriteWindow();

	BMessenger(fWriteWindow).SendMessage(message);
	fWriteWindow->Show();
}

/////////////////////////////////////////////////////////////////////////////////
// MessageReceived
//
//
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::MessageReceived(BMessage *msg)
{
	switch (msg->what){
		case kMENU_EDIT_FIND:
			openWindow(fFindWindow);
			break;

		case kMENU_THREAD_JUMP:
			openWindow(fJumpWindow);
			break;

		case kMSG_FIND:
			this->DoFind(msg, false);
			break;

		case kMENU_EDIT_FINDAGAIN:
			this->DoFind(msg, true);
			break;

		case kMENU_EDIT_OPENPREFERNCE:
			openWindow(fPrefWindow);
			break;

		case kMEG_WRITE_BUTTON:
			this->OpenWriteThreadWindow(msg);
			break;

		case kMSG_CLOSE_WRITE_WINDOW:
			fWriteWindow = NULL;
			break;
			
		case kUPDATEPREFS:
		case kMSG_BOOKMARK:
		case kMSG_JUMP:
		case kMENU_THREAD_REFREASH:
			BMessenger(fMainWindow).SendMessage(msg);
			break;
		
		case kNOT_INPLEMENTED:
			this->NotImplemented();
			break;

		default:
			BApplication::MessageReceived (msg);
			break;
	}
}

////////////////////////////////////////////////////////////////////////////////
// void a2chViewer::ArgvReceived()
// 引数をbookmarkの文字列とみなす。
//
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::ArgvReceived(int32 argc, char** argv)
{
	while (--argc) {
		++argv;
		if (argv[0][0] == '-') {
			if (argv[0][1] == '-') {
			// TODO long optionの処理
			} else {
			// TODO shourt optionの処理
			}
		}
		else this->PostBookmark(argv[0]);
	}
}
////////////////////////////////////////////////////////////////////////////////
// void a2chViewer::RefsReceived()
// zeta 2 スレ@713のBe名無しさんより。
//
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::RefsReceived(BMessage *msg)
{
	entry_ref ref;
	msg->FindRef("refs", &ref);
	BNode node(&ref);
	BString url;
	node.ReadAttrString("META:url", &url);
	this->PostBookmark(url.String());
}
////////////////////////////////////////////////////////////////////////////////
// void a2chViewer::PostBookmark()
// bookmarkメッセージをPostする。
//
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::PostBookmark(const char *url)
{
	BMessage msgbk(kMSG_BOOKMARK);
	msgbk.AddString("url", url);
	BMessenger(fMainWindow).SendMessage(&msgbk);
}
////////////////////////////////////////////////////////////////////////////////
// void a2chViewer::MakeSettingDir()
// 各種設定保存用ディレクトリを作成する。
//
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::MakeSettingDir()
{
	BDirectory subdir(kSETTING_PATH);
	if (subdir.InitCheck() != B_OK) {
		create_directory(kSETTING_PATH, 0777);
		subdir.SetTo(kSETTING_PATH);
	}

	subdir.CreateDirectory("BBS", NULL);
	subdir.CreateDirectory("2chCache", NULL);
	subdir.CreateDirectory("Bookmarks", NULL);
}
////////////////////////////////////////////////////////////////////////////////
// void a2chViewer::MakeDefault()
// アプリの設定default値の作成。
//
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::MakeDefault()
{
	// main window
	theSettings().SetRect(kSETTING_WINDOW_RECT, BRect(50, 30, 620, 400));
	// BBS
	theSettings().SetString(kSETTING_BBS_NAME, "2ch");
	theSettings().SetString(kSETTING_BBS_SOURCE, "menu2ch.net");
	//SplitPane
//	font_height height;
//	be_plain_font->GetHeight(&height);
//	theSettings().SetPoint(kSETTING_H_SPLITTER_POINT, BPoint(0, ( height.ascent + height.descent + height.leading+4) * 6));
//	theSettings().SetPoint(kSETTING_V_SPLITTER_POINT, BPoint (be_plain_font->StringWidth ("あ") * 9 + 12 + B_V_SCROLL_BAR_WIDTH, 0));

	//OffLine
	theSettings().SetBool(kSETTING_OFFLINE, kONLINE);
	
	//Font
	theSettings().SetString(DISPLAY_BOARD_FONT_NAME, "Konatu");
	theSettings().SetString(DISPLAY_BOARD_FONT_SIZE, "12");
	theSettings().SetString(DISPLAY_RESLIST_FONT_NAME, "Konatu");
	theSettings().SetString(DISPLAY_RESLIST_FONT_SIZE, "12");
	theSettings().SetString(DISPLAY_RES_FONT_NAME, "Konatu");
	theSettings().SetString(DISPLAY_RES_FONT_SIZE, "12");

	//thread display
	theSettings().SetString(DISPLAY_ALL_THREAD, "0");
	theSettings().SetString(DISPLAY_FIRST_THREAD, "0");
	theSettings().SetString(DISPLAY_LAST_THREAD, "1");
	theSettings().SetString(DISPLAY_THREAD_RANGE, "100");

	theSettings().SetString(GENERAL_CHACHE_PATH, kSETTING_PATH);
	theSettings().SetString(GENERAL_HISTORY_COUNT, "5");
	
	theSettings().SetString(GENERAL_BBS_LOAD, "1");
}
////////////////////////////////////////////////////////////////////////////////
// Alert
// エラーを知らせ、オフライン、オンラインのモード切替を行う。
//
////////////////////////////////////////////////////////////////////////////////
status_t
a2chViewer::Alert()
{
	const char *offLineMessage[] ={"オフラインでエラーが発生しました。","オンラインにする","キャンセル"};
	const char *onLineMessage[] ={"オンラインでエラーが発生しました","オフラインにする","キャンセル"};

	const char **message = (theSettings().GetBool(kSETTING_OFFLINE) == kONLINE ? onLineMessage : offLineMessage);

	int32 button = (new BAlert("",message[0], message[1], message[2]))->Go();
	
	if(button == 0){
		theSettings().SetBool(kSETTING_OFFLINE, theSettings().GetBool(kSETTING_OFFLINE) == kONLINE ? kOFFLINE : kONLINE);
		return B_OK;
	}
	
	return B_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
// OffLineAlert
// オフラインならオンラインにするよう警告する。
//
////////////////////////////////////////////////////////////////////////////////
status_t
a2chViewer::OffLineAlert()
{
	if(theSettings().GetBool(kSETTING_OFFLINE) == kONLINE)
		return B_OK;

	int32 button = (new BAlert("","オフラインです。","オンラインにする","OK"))->Go();
	
	if(button == 0){
		theSettings().SetBool(kSETTING_OFFLINE, kONLINE);
		return B_OK;
	}

	return B_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
// NotImplemented
// 未実装機能用アラート。
//
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::NotImplemented()
{
	(new BAlert(	"Not Implemented.",
" .,ｨ'^i^ﾄ,､\n" 
"　/y'´⌒ ヽ\n" 
" i[》《]iノﾉ）)〉　まだ未実装ですわ。\n" 
"　|!|(i´ヮ｀ﾉ!\n" 
"　と{2ch+}7う\n" 
"　 /|i__i|｀ｨﾌ\n" 
"　 `~じヽ)~",
	"OK"))->Go();

}
////////////////////////////////////////////////////////////////////////////////
//
//
//
////////////////////////////////////////////////////////////////////////////////
BBSHandler *
a2chViewer::CurReader()
{
	return 	fCurReader;
}
////////////////////////////////////////////////////////////////////////////////
// MakeReaderList
//
// 20060319;修正
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::MakeReaderList(BPopUpMenu *aMenu)
{
	for ( int32 i = 0; i < fReaderList->CountItems(); i++ ){
		BBSHandler *anItem = static_cast<BBSHandler *>(fReaderList->ItemAt(i));
		aMenu->AddItem(new BMenuItem(anItem->GetName(), new BMessage('kBBS')));
		if(anItem == fCurReader) {
			(aMenu->ItemAt(i))->SetMarked(true);
		}

	}
}
////////////////////////////////////////////////////////////////////////////////
//
//
//
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::SetCurReader(const char *name)
{
	for ( int32 i = 0; i < fReaderList->CountItems(); i++ ){
		BBSHandler *anItem = static_cast<BBSHandler *>(fReaderList->ItemAt(i));
		if(strcmp(anItem->GetName(), name) == 0){
		 fCurReader = anItem;
		 return;
		}
	} 
}
////////////////////////////////////////////////////////////////////////////////
// LoadReader
//
// 20060319:fReaderNameList削除
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::LoadReader()
{
	fReaderList = new BList;
	
#ifdef USE_2CH
	fReaderList->AddItem(new BBS2chReader);
#endif
#ifdef USE_PINKBBS
	fReaderList->AddItem(new BBSPinkchReader);
#endif
#ifdef USE_MACHIBBS
	fReaderList->AddItem(new BBSMachibbsReader);
#endif
#ifdef USE_LOCALDAT
	fReaderList->AddItem(new LocalDATReader);
#endif
#ifdef USE_MYBBS
	fReaderList->AddItem(new BBSMyReader);
#endif
	
	fCurReader = static_cast<BBSHandler *>(fReaderList->FirstItem());
}
////////////////////////////////////////////////////////////////////////////////
//
//
// 20060319:fReaderNameList削除
////////////////////////////////////////////////////////////////////////////////
void
a2chViewer::ReleaseReader()
{
	BBSHandler *anItem; 
	for ( int32 i = 0; (anItem = static_cast<BBSHandler *>(fReaderList->ItemAt(i))) != NULL; i++ ) 
		delete anItem;
	delete fReaderList;
	
}

